<template>
  <div class="filter-options">
    <input type="text" class="input" ref="input" placeholder="请输入关键字" v-model="keyword" @input="handleInput" />
    <div class="options" ref="options"></div>
    <div class="btns">
      <div class="btn submit" @click="handleSubmit">筛选</div>
      <div class="btn" @click="handleSelectAll">全选</div>
      <div class="btn" @click="handleSelectNone">全不选</div>
    </div>
  </div>
</template>

<script>
export default {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    data: {
      type: Array,
      required: true,
    },
    value: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      selected: [],
      jhVScroller: null,
      scopedHash: {},
      keyword: '',
      pagesize: 5,
      pageno: 0,
    };
  },
  computed: {
    filterData() {
      return this.data.filter(o => {
        if (!this.keyword) {
          return true;
        } else {
          return (o || '').toLowerCase().includes(this.keyword.toLowerCase());
        }
      });
    },
  },
  mounted() {
    this.jhVScroller = new window.JhVirtualScroll(this.$refs.options, {
      fetch: this.getData,
      skeleton: this.getSkeleton,
      render: this.toRender,
    });
  },
  methods: {
    getData() {
      return this.filterData.slice(
        (++this.pageno - 1) * this.pagesize,
        this.pageno * this.pagesize,
      );
    },
    getSkeleton() {
      var div = document.createElement('div');
      div.textContent = 'loading...';
      const styles = {
        width: '100%',
        lineHeight: '32px',
        boxSizing: 'border-box',
        padding: '0 5px',
        color: 'gray',
        fontSize: '12px',
        cursor: 'wait',
      };
      Object.keys(styles).forEach(key => {
        div.style[key] = styles[key];
      });
      div.title = '请稍候';
      return div;
    },
    toRender(data) {
      const div = document.createElement('div');
      div.classList = 'item';
      if (this.selected.includes(data)) {
        div.classList.add('selected');
      }
      div.textContent = data;
      div.addEventListener('click', () => {
        const index = this.selected.indexOf(data);
        if (index > -1) {
          div.classList.remove('selected');
          this.selected.splice(index, 1);
        } else {
          div.classList.add('selected');
          this.selected.push(data);
        }
      });
      this.injectionHash(div);
      return div;
    },
    injectionHash(node) {
      if (
        this.scopedHash !== null &&
        Object.keys(this.scopedHash).length === 0
      ) {
        Object.keys(this.$refs.options.dataset).forEach(key => {
          this.$set(this.scopedHash, key, '');
        });
        if (Object.keys(this.scopedHash).length === 0) {
          this.scopedHash = null;
        }
      }
      Object.keys(this.scopedHash || {}).forEach(hash => {
        node.dataset[hash] = '';
        if (node.childNodes.length > 0) {
          node.childNodes.forEach(child => {
            if (child.nodeType === 1) {
              this.injectionHash(child);
            }
          });
        }
      });
    },
    handleInput() {
      this.$nextTick(() => {
        if (this.jhVScroller) {
          this.jhVScroller.onReload(() => {
            this.pageno = 0;
          });
        }
      });
    },
    handleSelectAll() {
      this.selected = [...this.filterData];
      this.handleInput();
    },
    handleSelectNone() {
      this.selected = [];
      this.handleInput();
    },
    handleSubmit() {
      this.$emit('change', this.selected);
    },
  },
  watch: {
    value: {
      handler() {
        this.selected = [...this.value];
        if (this.jhVScroller) {
          this.jhVScroller.onReload(() => {
            this.pageno = 0;
          });
        }
      },
      immediate: true,
    },
    filterData: {
      handler(newValue, oldValue) {
        if (newValue.length > 0) {
          if (this.jhVScroller) {
            this.jhVScroller.onReload(() => {
              this.pageno = 0;
            });
          }
        }
      },
      immediate: true,
    },
  },
};
</script>

<style lang="less" scoped>
.filter-options {
  line-height: normal;
  color: #333;
  font-weight: normal;
  .input {
    border: 1px solid #ddd;
    outline: none;
    border-radius: 4px;
    padding: 5px 8px;
    margin: 5px 0;
    font-size: 12px;
  }
  .options {
    min-height: 40px;
    height: 250px;
    overflow: auto;
    padding: 3px 0;
    &::-webkit-scrollbar {
      width: 6px;
    }
    &::-webkit-scrollbar-thumb {
      border-radius: 6px;
      background: rgba(144, 146, 152, 0.5);
    }
    &::-webkit-scrollbar-track {
      border-radius: 6px;
      background: transparent;
    }
    .item {
      font-size: 12px;
      padding: 0 6px;
      position: relative;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      color: #606266;
      width: 100%;
      height: 25px;
      line-height: 25px;
      box-sizing: border-box;
      cursor: pointer;
      &.selected {
        color: #409eff;
        font-weight: 700;
      }
      &:hover:not(.is-disabled) {
        background: #f5f7fa;
      }
    }
  }
  .btns {
    font-size: 14px;
    padding: 12px 5px;
    display: flex;
    justify-content: center;
    .btn {
      flex: 1;
      text-align: right;
      cursor: pointer;
      color: #888;
      &:hover {
        color: #333;
      }
      &.submit {
        text-align: left;
        color: #409eff;
        font-weight: 700;
      }
    }
  }
}
</style>

